/*------------------------------------------------------------
  一个“最小可运行”的 Win32 宽字符示例
  作用：告诉你窗口、文字、按钮、点击事件在 Win32 里长什么样
  编译：g++ main.cpp -mwindows
  ------------------------------------------------------------*/

#define UNICODE                 // 强制使用宽字符
#define _UNICODE
#include <windows.h>

/*------------------------------------------------------------
  1. 先声明一个“窗口过程”——其实就是窗口的“总机小姐”
     所有消息（键盘、鼠标、绘图……）都会先打到这里，
     我们再决定要不要“转接”给系统默认处理。
  ------------------------------------------------------------*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);

/*------------------------------------------------------------
  2. 程序的“真入口”不是 main，而是 WinMain
     四个参数都是操作系统免费送给我们的：
        hInstance  → 本程序的“身份证”
        hPrev      → 历史遗留，现在永远 NULL
        lpCmdLine  → 命令行字符串
        nShowCmd   → 窗口一开始要怎么显示（最大化/最小化/正常）
  ------------------------------------------------------------*/
int WINAPI wWinMain(HINSTANCE hInstance,
                    HINSTANCE,
                    PWSTR,
                    int nShowCmd)
{
    /*--------------------------------------------------------
      2-1  注册窗口类
            相当于告诉操作系统：“我要开一间叫 MyClass 的店，
            门口招牌长什么样、谁来接待客人都写在这张表上”
    --------------------------------------------------------*/
    const wchar_t CLASS_NAME[] = L"MyClass";

    WNDCLASSEXW wc{ sizeof(wc) };
    wc.style         = CS_HREDRAW | CS_VREDRAW;   // 尺寸变化就重画
    wc.lpfnWndProc   = WndProc;                   // “接待员”地址
    wc.hInstance     = hInstance;                 // 身份证
    wc.hCursor       = LoadCursorW(nullptr, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszClassName = CLASS_NAME;

    if (!RegisterClassExW(&wc))
    {
        MessageBoxW(nullptr, L"注册窗口类失败", L"错误", MB_ICONERROR);
        return 0;
    }

    /*--------------------------------------------------------
      2-2  真正“把窗户造出来”
            CreateWindowExW 的 12 个参数猛一看吓人，
            其实就一句话：在哪个类、标题、风格、位置、大小、父窗口...
    --------------------------------------------------------*/
    HWND hwnd = CreateWindowExW(
        0,                        // 扩展风格
        CLASS_NAME,               // 刚才注册的类名
        L"Win32 小Demo（宽字符版）", // 标题
        WS_OVERLAPPEDWINDOW,      // 普通带标题栏可最大/最小化的窗口
        CW_USEDEFAULT, CW_USEDEFAULT, 500, 350,
        nullptr, nullptr, hInstance, nullptr);

    if (!hwnd)
    {
        MessageBoxW(nullptr, L"创建窗口失败", L"错误", MB_ICONERROR);
        return 0;
    }

    /*--------------------------------------------------------
      2-3  把窗户推到台前 + 强制刷新一次
    --------------------------------------------------------*/
    ShowWindow(hwnd, nShowCmd);
    UpdateWindow(hwnd);

    /*--------------------------------------------------------
      2-4  “消息循环”——程序的心脏
            GetMessageW 像前台小妹，永远坐在那里等消息；
            TranslateMessage 把键盘扫描码翻译成字符；
            DispatchMessageW 把消息送给“窗口过程”。
    --------------------------------------------------------*/
    MSG msg;
    while (GetMessageW(&msg, nullptr, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessageW(&msg);
    }
    return (int)msg.wParam;
}

/*------------------------------------------------------------
  3. 窗口过程 —— 前面说的“总机小姐”正式上班
     每个窗口消息都会带一个编号（msg），
     我们根据编号决定干什么活：
        WM_CREATE   → 窗口刚诞生
        WM_PAINT    → 需要重画
        WM_COMMAND  → 控件被点
        WM_DESTROY  → 关闭窗口
  ------------------------------------------------------------*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    /* 按钮的“句柄”——相当于按钮的身份证号，创建后保存起来 */
    static HWND hBtn = nullptr;

    switch (msg)
    {
    /*--------------------------------------------------------
      3-1  窗口一出生，就给它“贴”一个按钮上去
    --------------------------------------------------------*/
    case WM_CREATE:
    {
        hBtn = CreateWindowExW(
            0, L"BUTTON",          // 系统预定义的“按钮”类
            L"点我试试",           // 按钮文字
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            50, 50, 120, 30,       // 位置、大小
            hwnd,                  // 父窗口
            (HMENU)1001,           // 控件ID（随便给，只要>0）
            GetModuleHandleW(nullptr), nullptr);
        return 0;
    }

    /*--------------------------------------------------------
      3-2  画字——用“GDI 设备上下文”在客户区写字
    --------------------------------------------------------*/
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);

        /* 简单地在左上角写一行字 */
        TextOutW(hdc, 50, 100, L"你好，Win32！", 8);

        EndPaint(hwnd, &ps);
        return 0;
    }

    /*--------------------------------------------------------
      3-3  按钮被点：WM_COMMAND 消息
            LOWORD(wParam) 是控件ID
    --------------------------------------------------------*/
    case WM_COMMAND:
        if (LOWORD(wp) == 1001)   // 就是我们刚才的按钮
            MessageBoxW(hwnd, L"按钮被点了！", L"提示", MB_OK);
        return 0;

    /*--------------------------------------------------------
      3-4  右上角“X”被点
    --------------------------------------------------------*/
    case WM_DESTROY:
        PostQuitMessage(0);   // 告诉消息循环：可以下班了
        return 0;
    }

    /* 其余消息交给系统默认处理 */
    return DefWindowProcW(hwnd, msg, wp, lp);
}